Control flow checking (CFC) can be used to verify that the instructions of a program are read without error and in the right order. These checking schemes of the CFC type can be divided into two groups, namely schemes using embedded signatures (ESM: Embedded Signature Monitoring) and those using disjoint signatures (DSM).
In the first case, the reference signatures and the checking directives are embedded in the code to be monitored, in the form of special instructions. In the case of disjoint signatures, the reference signatures and the checking directives are stored in another part of the system memory or in a disjoint memory, which has the drawback of increasing the cost of memory.
Moreover, the monitoring program is generally implemented in a coprocessor commonly dubbed a “Watchdog” and this coprocessor in addition to the fact that it needs to access the memory in an autonomous manner so as not to degrade the performance of the system, needs to also maintain tight synchronization with the processor executing the program code to be monitored.
To perform the control flow checking, the monitoring program needs to be perfectly synchronized with the program to be monitored, in order to be capable of tracking its execution, for the purpose, in particular, of checking the signatures of the basic blocks of which the program is composed, and the transfers of control flows from one basic block to another, generally by means of jump or branch instructions.
Generally, a “Watchdog” instruction is associated with the first and with the last instruction of each basic block of the program to be monitored. At the end of a basic block terminating on a branch instruction, the coprocessor is capable of tracking the processor by itself branching to its own destination instruction corresponding to the target instruction to which the processor has jumped.
The coprocessor can then check that the processor has actually jumped to the correct instruction because the destination instruction of the coprocessor contains the address of the corresponding target instruction in the program of the processor.
It may be seen, therefore, that the synchronization between the processor and the coprocessor is based on the link between the processor instructions and the coprocessor instructions. This is possible only if the target of each branch of the code to be monitored is known before its execution, so that the corresponding coprocessor branch instruction can be created.
However, indirect branches may be present in the program code to be monitored. As is well known to those skilled in the art, a direct branch is a branch whose branch instruction target address can be calculated on the basis of the instruction alone (the code and the address).
Indirect branches are all those branches which are not direct, for example, those for which the calculation of the target address uses the values of one or more registers. Thus, for an indirect branch, the target address cannot be known solely on the basis of the instructions of the program code, since, by definition, this address depends on the execution of the program code.
Moreover, an indirect branch may have multiple target addresses. Also, a coprocessor of the “Watchdog” type is currently capable of managing only a single target address encoded in the branch instruction of its program code.
This problem is particularly significant in the context of DSM methods. Consequently, most DSM methods do not deal with the matter of indirect branches, meaning that the code to be monitored cannot contain any of these indirect branches.
However, indirect branches are commonly used in embedded programs, since they can be used to reduce the size of the code and the cycle penalties. In some cases of indirect branching, a set of legitimate targets can be determined before the execution of the program. In this case, the coprocessor program can be constructed in full. However, the problem of managing multiple targets remains.
In fact, the addresses to which the coprocessor has to branch are currently encoded in branch instructions which do not offer enough bits to encode multiple addresses.
Furthermore, even if multiple addresses can be stored, using a table for example, each of them has to be linked with the corresponding address of the processor; otherwise, the coprocessor cannot know which address to branch to.
Moreover, in addition to the indirect branches whose multiple targets are predictable, there may exist indirect branches whose targets are not predictable, since for example, the addresses of these targets may depend on one or more parameters whose values may themselves depend on the execution of the program.
In fact in theory the address of any target is predictable. But in practice in certain cases, such as in particular that mentioned hereinabove, the possibilities can become so numerous that it becomes almost impossible to provide for all the possible branches. This is the reason why these indirect branches are then referred to as “non-predictable”.
Among these “non-predictable” indirect branches may be cited the indirect jump instructions. Among the other possible indirect branches may also be cited the instructions of function calls whose branches may also depend in certain cases on parameters having non-predictable values.
A need therefore exists to generate a program code for monitoring a program code to be monitored which can manage in a simple and effective manner the indirect branches present in the program code to be monitored, and in particular, those leading to multiple targets, whether or not these indirect branches are predictable.